aboutsummaryrefslogtreecommitdiff
path: root/examples/portfolio/src/pages/work/[...slug].astro
diff options
context:
space:
mode:
Diffstat (limited to 'examples/portfolio/src/pages/work/[...slug].astro')
-rw-r--r--examples/portfolio/src/pages/work/[...slug].astro152
1 files changed, 152 insertions, 0 deletions
diff --git a/examples/portfolio/src/pages/work/[...slug].astro b/examples/portfolio/src/pages/work/[...slug].astro
new file mode 100644
index 000000000..90eb3ba8d
--- /dev/null
+++ b/examples/portfolio/src/pages/work/[...slug].astro
@@ -0,0 +1,152 @@
+---
+import { type CollectionEntry, getCollection } from 'astro:content';
+
+import BaseLayout from '../../layouts/BaseLayout.astro';
+
+import ContactCTA from '../../components/ContactCTA.astro';
+import Hero from '../../components/Hero.astro';
+import Icon from '../../components/Icon.astro';
+import Pill from '../../components/Pill.astro';
+import { render } from 'astro:content';
+
+interface Props {
+ entry: CollectionEntry<'work'>;
+}
+
+// This is a dynamic route that generates a page for every Markdown file in src/content/
+// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
+// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
+export async function getStaticPaths() {
+ const work = await getCollection('work');
+ return work.map((entry) => ({
+ params: { slug: entry.id },
+ props: { entry },
+ }));
+}
+
+const { entry } = Astro.props;
+const { Content } = await render(entry);
+---
+
+<BaseLayout title={entry.data.title} description={entry.data.description}>
+ <div class="stack gap-20">
+ <div class="stack gap-15">
+ <header>
+ <div class="wrapper stack gap-2">
+ <a class="back-link" href="/work/"><Icon icon="arrow-left" /> Work</a>
+ <Hero title={entry.data.title} align="start">
+ <div class="details">
+ <div class="tags">
+ {entry.data.tags.map((t) => <Pill>{t}</Pill>)}
+ </div>
+ <p class="description">{entry.data.description}</p>
+ </div>
+ </Hero>
+ </div>
+ </header>
+ <main class="wrapper">
+ <div class="stack gap-10 content">
+ {entry.data.img && <img src={entry.data.img} alt={entry.data.img_alt || ''} />}
+ <div class="content">
+ <Content />
+ </div>
+ </div>
+ </main>
+ </div>
+ <ContactCTA />
+ </div>
+</BaseLayout>
+
+<style>
+ header {
+ padding-bottom: 2.5rem;
+ border-bottom: 1px solid var(--gray-800);
+ }
+
+ .back-link {
+ display: none;
+ }
+
+ .details {
+ display: flex;
+ flex-direction: column;
+ padding: 0.5rem;
+ gap: 1.5rem;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .tags {
+ display: flex;
+ gap: 0.5rem;
+ }
+
+ .description {
+ font-size: var(--text-lg);
+ max-width: 54ch;
+ }
+
+ .content {
+ max-width: 65ch;
+ margin-inline: auto;
+ }
+
+ .content > :global(* + *) {
+ margin-top: 1rem;
+ }
+
+ .content :global(h1),
+ .content :global(h2),
+ .content :global(h3),
+ .content :global(h4),
+ .content :global(h5) {
+ margin: 1.5rem 0;
+ }
+
+ .content :global(img) {
+ border-radius: 1.5rem;
+ box-shadow: var(--shadow-sm);
+ background: var(--gradient-subtle);
+ border: 1px solid var(--gray-800);
+ }
+
+ .content :global(blockquote) {
+ font-size: var(--text-lg);
+ font-family: var(--font-brand);
+ font-weight: 600;
+ line-height: 1.1;
+ padding-inline-start: 1.5rem;
+ border-inline-start: 0.25rem solid var(--accent-dark);
+ color: var(--gray-0);
+ }
+
+ .back-link,
+ .content :global(a) {
+ text-decoration: 1px solid underline transparent;
+ text-underline-offset: 0.25em;
+ transition: text-decoration-color var(--theme-transition);
+ }
+
+ .back-link:hover,
+ .back-link:focus,
+ .content :global(a:hover),
+ .content :global(a:focus) {
+ text-decoration-color: currentColor;
+ }
+
+ @media (min-width: 50em) {
+ .back-link {
+ display: block;
+ align-self: flex-start;
+ }
+
+ .details {
+ flex-direction: row;
+ gap: 2.5rem;
+ }
+
+ .content :global(blockquote) {
+ font-size: var(--text-2xl);
+ }
+ }
+</style>